<!DOCTYPE html>
<html lang="en-US">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <title>Vue | YTBlog</title>
    <meta name="generator" content="VuePress 1.5.2">
    
    <meta name="description" content="前端技术分享">
    <link rel="preload" href="/ytblog/assets/css/0.styles.cb920d31.css" as="style"><link rel="preload" href="/ytblog/assets/js/app.5ba5dcf6.js" as="script"><link rel="preload" href="/ytblog/assets/js/2.f25dafc3.js" as="script"><link rel="preload" href="/ytblog/assets/js/13.fbec9428.js" as="script"><link rel="prefetch" href="/ytblog/assets/js/10.5a02d3b2.js"><link rel="prefetch" href="/ytblog/assets/js/11.44a85492.js"><link rel="prefetch" href="/ytblog/assets/js/12.66c94e70.js"><link rel="prefetch" href="/ytblog/assets/js/3.1ec314c7.js"><link rel="prefetch" href="/ytblog/assets/js/4.6f6a54bd.js"><link rel="prefetch" href="/ytblog/assets/js/5.64df639e.js"><link rel="prefetch" href="/ytblog/assets/js/6.60c7b6d3.js"><link rel="prefetch" href="/ytblog/assets/js/7.7c06f209.js"><link rel="prefetch" href="/ytblog/assets/js/8.f6875229.js"><link rel="prefetch" href="/ytblog/assets/js/9.6f0d250c.js">
    <link rel="stylesheet" href="/ytblog/assets/css/0.styles.cb920d31.css">
  </head>
  <body>
    <div id="app" data-server-rendered="true"><div class="theme-container"><header class="navbar"><div class="sidebar-button"><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" role="img" viewBox="0 0 448 512" class="icon"><path fill="currentColor" d="M436 124H12c-6.627 0-12-5.373-12-12V80c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12z"></path></svg></div> <a href="/ytblog/" class="home-link router-link-active"><!----> <span class="site-name">YTBlog</span></a> <div class="links"><div class="search-box"><input aria-label="Search" autocomplete="off" spellcheck="false" value=""> <!----></div> <nav class="nav-links can-hide"><div class="nav-item"><a href="/ytblog/" class="nav-link">
  主页
</a></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="练手小项目" class="dropdown-title"><span class="title">练手小项目</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><!----> <a href="/ytblog/HTML/" class="nav-link">
  HTML&amp;CSS
</a></li><li class="dropdown-item"><!----> <a href="/ytblog/JavaScript/" class="nav-link">
  JavaScript
</a></li><li class="dropdown-item"><!----> <a href="/ytblog/jquery/" class="nav-link">
  jquery
</a></li><li class="dropdown-item"><!----> <a href="/ytblog/vue/" aria-current="page" class="nav-link router-link-exact-active router-link-active">
  vue
</a></li></ul></div></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="前端一些概念理解" class="dropdown-title"><span class="title">前端一些概念理解</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><!----> <a href="/ytblog/CSS/" class="nav-link">
  知识点整理
</a></li><li class="dropdown-item"><!----> <a href="/ytblog/ES6/" class="nav-link">
  读书笔记
</a></li></ul></div></div> <!----></nav></div></header> <div class="sidebar-mask"></div> <aside class="sidebar"><nav class="nav-links"><div class="nav-item"><a href="/ytblog/" class="nav-link">
  主页
</a></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="练手小项目" class="dropdown-title"><span class="title">练手小项目</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><!----> <a href="/ytblog/HTML/" class="nav-link">
  HTML&amp;CSS
</a></li><li class="dropdown-item"><!----> <a href="/ytblog/JavaScript/" class="nav-link">
  JavaScript
</a></li><li class="dropdown-item"><!----> <a href="/ytblog/jquery/" class="nav-link">
  jquery
</a></li><li class="dropdown-item"><!----> <a href="/ytblog/vue/" aria-current="page" class="nav-link router-link-exact-active router-link-active">
  vue
</a></li></ul></div></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="前端一些概念理解" class="dropdown-title"><span class="title">前端一些概念理解</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><!----> <a href="/ytblog/CSS/" class="nav-link">
  知识点整理
</a></li><li class="dropdown-item"><!----> <a href="/ytblog/ES6/" class="nav-link">
  读书笔记
</a></li></ul></div></div> <!----></nav>  <ul class="sidebar-links"><li><section class="sidebar-group depth-0"><p class="sidebar-heading open"><span>Vue</span> <!----></p> <!----></section></li></ul> </aside> <main class="page"> <div class="theme-default-content content__default"><h1 id="vue"><a href="#vue" class="header-anchor">#</a> Vue</h1> <p><a href="https://ucas-yutao.gitee.io/yt_project/vue_todolist/" target="_blank" rel="noopener noreferrer">todolist<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg></a></p> <p>用vue重写了一遍todolist，有一些细节值得注意。</p> <h4 id="数据设计"><a href="#数据设计" class="header-anchor">#</a> 数据设计</h4> <p>有两种想法：</p> <p>第一种是只有一个todolist数组，内部用标记区别是否完成，ID是多少（标记删除），内容是什么：</p> <p>[{id:arr.length , content:&quot;吃饭&quot; ，done：“true”}]这种形式，这种形式需要用computed根据done生成done和doing两个数组。</p> <p>第二种是data有两个数组，一个是doing，一个是done。好处是不需要ID，不需要再computed里遍历。</p> <p>最终选择了第二种。</p> <h4 id="完成与未完成的数量"><a href="#完成与未完成的数量" class="header-anchor">#</a> 完成与未完成的数量</h4> <p>两种写法：</p> <p>第一种是用计算属性，动态计算一个数量</p> <div class="language- extra-class"><pre class="language-text"><code>&lt;div class=&quot;num&quot;&gt;{{doingnum}}&lt;/div&gt;
  computed: {
    doingnum: function () {
      return this.doing.length;
    },
</code></pre></div><p>第二种是直接再上面用</p> <div class="language- extra-class"><pre class="language-text"><code>&lt;div class=&quot;num&quot;&gt;{{done.length}}&lt;/div&gt;
</code></pre></div><h4 id="核心列表部分"><a href="#核心列表部分" class="header-anchor">#</a> 核心列表部分</h4> <div class="language- extra-class"><pre class="language-text"><code>          &lt;transition-group
            name=&quot;custom-classes-transition&quot;
            enter-active-class=&quot;animated tada&quot;
            leave-active-class=&quot;animated bounceOutRight&quot;
          &gt;
            &lt;div
              class=&quot;toItem&quot;
              v-for=&quot;(item,index) in doing&quot;
              :data-index=&quot;index&quot;
              v-bind:key=&quot;'doing'+index&quot;
            &gt;
              &lt;input type=&quot;checkbox&quot; @click.prevent=&quot;doingcheck(index)&quot; v-bind:key=&quot;index&quot; /&gt;
              &lt;div class=&quot;content&quot;&gt;{{item}}&lt;/div&gt;
              &lt;div class=&quot;del&quot; @click=&quot;deleteDoing(index)&quot;&gt;删除&lt;/div&gt;
            &lt;/div&gt;
          &lt;/transition-group&gt;
</code></pre></div><p>一项项解释：</p> <p><strong>transition-group</strong>：用这个标签包裹会变化的盒子，即可实现动画，我这里用的直接是vue官网示范的animate的代码。</p> <p><strong>v-for循环</strong>：用vuecli的话item和index必须要括号包起来，不然会报错。</p> <p><strong>key</strong>：必须绑定，不然报错</p> <p><strong>data-index</strong>：这里其实无所谓，原本打算用这个找到被删除的下标的，vue用更简单的写法。</p> <p><strong>prevent</strong>：要组织checkbox的默认事件，不然会出现一些奇怪的现象，在完成列表了点了盒子，那条不在了，但是新占据位置的item的checked会没有。</p> <p><strong>@click.prevent=&quot;doingcheck(index)&quot;</strong>：传参，如果不传默认就是正常的event传进去了。</p> <h4 id="输入部分"><a href="#输入部分" class="header-anchor">#</a> 输入部分</h4> <div class="language- extra-class"><pre class="language-text"><code>        &lt;input
          type=&quot;text&quot;
          v-model=&quot;inputValue&quot;
          @keydown.enter=&quot;enterEven&quot;
          id=&quot;input&quot;
          placeholder=&quot;请输入待办事项&quot;
        /&gt;
</code></pre></div><p>在data里设置inputValue = “”</p> <h4 id="各种按钮事件"><a href="#各种按钮事件" class="header-anchor">#</a> 各种按钮事件</h4> <div class="language- extra-class"><pre class="language-text"><code>    doingcheck: function (i) {
      this.done.push(this.doing[i]);
      this.doing.splice(i, 1);
</code></pre></div><p>事件都把index传进来了，直接用数组的方法操作就行。</p> <h4 id="数据存储"><a href="#数据存储" class="header-anchor">#</a> 数据存储</h4> <p>通过watch监听两个数组的变化，每次变化都把locoStorage更新</p> <div class="language- extra-class"><pre class="language-text"><code>  watch: {
    doing: function (newarr) {
      localStorage.doing = JSON.stringify(newarr);
      console.log(&quot;doing&quot;, localStorage.doing);
    },
    done: function (newarr) {
      localStorage.done = JSON.stringify(newarr);
      console.log(&quot;done&quot;, localStorage.done);
    },
  },
</code></pre></div><p>在mounted钩子函数里把数据恢复</p> <div class="language- extra-class"><pre class="language-text"><code>  mounted: function () {
    this.doing = localStorage.doing ? JSON.parse(localStorage.doing) : [];
    this.done = localStorage.done ? JSON.parse(localStorage.done) : [];
    this.ytXys();
  },
</code></pre></div><h4 id="响应式："><a href="#响应式：" class="header-anchor">#</a> 响应式：</h4> <p>在上方mounted钩子函数调用响应式，在methods里定义了一个响应式函数。</p> <div class="language- extra-class"><pre class="language-text"><code>    ytXys: function () {
      let htmlDom = document.querySelector(&quot;html&quot;);
      var userAgent = navigator.userAgent;
      //userAgent.indexOf(&quot;iPhone&quot;),通过此方法可以获取iphone在字符中的索引值
      htmlDom.className = &quot;&quot;;
      if (userAgent.indexOf(&quot;iPhone&quot;) != -1) {
        //console.log(iphone)
        htmlDom.classList.add(&quot;iphone&quot;);
      } else if (userAgent.indexOf(&quot;Android&quot;) != -1) {
        //console.log(iphone)
        htmlDom.classList.add(&quot;android&quot;);
      } else if (userAgent.indexOf(&quot;iPad&quot;) != -1) {
        //console.log(iphone)
        htmlDom.classList.add(&quot;ipad&quot;);
      } else {
        htmlDom.classList.add(&quot;pc&quot;);
      }
      var screenWidth = window.innerWidth;
      var danwei = screenWidth / 3.75; //屏幕的宽度/设计稿占满全屏的宽度为多少rem
      htmlDom.style.fontSize = danwei + &quot;px&quot;;
    }
</code></pre></div><p>通过动态调整单位rem大小来实现响应式。</p> <h4 id="窗口改变事件监听"><a href="#窗口改变事件监听" class="header-anchor">#</a> 窗口改变事件监听</h4> <p>这个函数应该放在main.js里，放在mounted里报错。</p> <div class="language- extra-class"><pre class="language-text"><code>window.onresize = function() {
  let htmlDom = document.querySelector(&quot;html&quot;);
  var userAgent = navigator.userAgent;
  //userAgent.indexOf(&quot;iPhone&quot;),通过此方法可以获取iphone在字符中的索引值
  htmlDom.className = &quot;&quot;;
  if (userAgent.indexOf(&quot;iPhone&quot;) != -1) {
    //console.log(iphone)
    htmlDom.classList.add(&quot;iphone&quot;);
  } else if (userAgent.indexOf(&quot;Android&quot;) != -1) {
    //console.log(iphone)
    htmlDom.classList.add(&quot;android&quot;);
  } else if (userAgent.indexOf(&quot;iPad&quot;) != -1) {
    //console.log(iphone)
    htmlDom.classList.add(&quot;ipad&quot;);
  } else {
    htmlDom.classList.add(&quot;pc&quot;);
  }
  var screenWidth = window.innerWidth;
  var danwei = screenWidth / 3.75; //屏幕的宽度/设计稿占满全屏的宽度为多少rem
  htmlDom.style.fontSize = danwei + &quot;px&quot;;
};
</code></pre></div></div> <footer class="page-edit"><!----> <!----></footer> <!----> </main></div><div class="global-ui"></div></div>
    <script src="/ytblog/assets/js/app.5ba5dcf6.js" defer></script><script src="/ytblog/assets/js/2.f25dafc3.js" defer></script><script src="/ytblog/assets/js/13.fbec9428.js" defer></script>
  </body>
</html>
